package com.tool.grab.vpn.header;

import java.util.HashMap;
import java.util.Map;

/**
 * HTTP报文格式
 * ｜－－－－－－－－－－－－－－－－－－－－－－－－－｜
 * ｜                      请求行                      ｜
 * ｜           （请求方法 请求URL HTTP版本）          ｜
 * ｜－－－－－－－－－－－－－－－－－－－－－－－－－｜
 * ｜                      报文头                      ｜
 * ｜           （一些请求状态和主机等信息）           ｜
 * ｜－－－－－－－－－－－－－－－－－－－－－－－－－｜
 * ｜                      报文体                      ｜
 * ｜                (数据报的内容部分)                ｜
 * ｜－－－－－－－－－－－－－－－－－－－－－－－－－｜
 * 请求行包括三个参数 依次为
 * 请求方法（常见的有 POST GET 这也是大多数浏览器支持的格式）
 * 请求URL 与HOST连接组成完整的请求路径
 * HTTP版本 标明所使用的HTTP版本号及协议名称
 * 报文头内包含一些服务器或客户端的请求属性
 * 具体内容参见 http://tools.jb51.net/table/http_header
 * 报文体中包含实际请求的内容或响应的数据
 * HTTP报文中每个部分用 回车符和换行符(\\r\\n)分割
 * 请求行与报文体各占一部分 报文头中每个属性对占一个部分
 * 请求行部分每个属性用空格隔开
 * 报文头部分每个属性对之间用‘：’（冒号）+‘ ’（空格）隔开
 * 报文体部分每个属性对用‘=’（等号）连接，属性间用‘&’（符号与）连接
 *
 * 由于https服务器方需要ssl加密，其需服务器申请AC证书 需要花钱
 * 所以https就不分析了。
 */

public class HttpPacket extends Packet{
    private boolean isHttp;
    private boolean isHttps;
    private boolean isOther;
    private String requestMethod;
    private String requestUrl;
    private String httpVersion;
    private String httpHost;
    private String httpUrl;
    private String dataLien;
    private String[] keyLines;
    private Map<String,String> keys = new HashMap<>();
    private Map<String,String> datas = new HashMap<>();

    public HttpPacket(byte[] bytes, int... parameters) {
        super(bytes, parameters);
        parse();
    }

    /**
     * 解析数据
     *  G : GET
     *  H : HEAD
     *  P : POST
     *  D : DELETE
     *  O : OPTIONS
     *  T : TRACE
     *  C : CONNECT
     */
    private void parse(){
        switch (bytes[offset]){
            case 'G':
            case 'H':
            case 'P':
            case 'D':
            case 'O':
            case 'T':
            case 'C':
                isHttp = true;
                isHttps = false;
                parseHttp();
                break;
            case 0x16:
                isHttp = false;
                isHttps = true;
                break;
                default:
                    isOther = true;
                    isHttp = false;
                    isHttps = false;
        }
    }

    private void parseHttp(){
        if(validLength - offset < 10) return;
        String dataString = new String(bytes,offset,validLength);
        keyLines = dataString.split("\\r\\n");
        for(int i = 0; i < keyLines.length; i++){
            if(i == 0){
                String requestLine = keyLines[i].trim();
                String[] data = requestLine.split(" ");

                if(data.length > 0){
                    requestMethod = data[0];
                }

                if(data.length > 1){
                    requestUrl = data[1];
                }

                if(data.length >= 2){
                    httpVersion = data[2];
                }
            }else if(i == keyLines.length - 1){
                dataLien = keyLines[keyLines.length - 1].trim();
                if(dataLien.isEmpty())return;
                String[] data = dataLien.split("&");
                for(int j = 0;j < data.length;j++){
                    if(data[i].indexOf("=") != -1){
                        String[] keys = data[i].trim().split("=",2);
                        if(keys[0].isEmpty())continue;
                        if(keys.length == 1){
                           datas.put(keys[0].trim(),"");
                        }else
                        if(keys.length == 2){
                            datas.put(keys[0].trim(),keys[1].trim());
                        }
                    }
                }

            }else{
                String requestLine = keyLines[i].trim();
                if(requestLine.indexOf(": ") != -1){
                    String[] data = requestLine.split(": ",2);
                    String key = data[0].trim();
                    String value = data[1].trim();
                    if(key.isEmpty())continue;
                    keys.put(key,value);

                    if(key.equals("host")){
                        httpHost = value;
                        if(requestUrl != null) httpUrl = "http://" + httpHost+"/" + requestUrl;
                    }
                }
            }
        }
    }

    public boolean isHttp() {
        return isHttp;
    }

    public boolean isHttps() {
        return isHttps;
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public String getHttpVersion() {
        return httpVersion;
    }

    public String getHttpHost() {
        return httpHost;
    }

    public String getHttpUrl() {
        return httpUrl;
    }

    public String getDataLien() {
        return dataLien;
    }

    public boolean isOther() {
        return isOther;
    }

    public Map<String, String> getKeys() {
        return keys;
    }

    public Map<String, String> getDatas() {
        return datas;
    }
}
